package org.luo.lan.server.factory;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.luo.lan.server.constants.AttrConstants;
import org.luo.lan.server.handlers.ServerProxyHandler;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;

@Slf4j
public class SessionFactory {
    public static SessionFactory INSTANCE = new SessionFactory();
    private Map<String,NioSocketChannel> sessionChannelMap = new ConcurrentHashMap<>();

    private SessionFactory(){}

    public String createSession(NioSocketChannel channel){
        String sessionKey = getSeesionKey();
        while (sessionChannelMap.putIfAbsent(sessionKey, channel) != null) {
            sessionKey = getSeesionKey();
        }
        log.debug("新增sessionKey={}，channel={}",sessionKey,channel);
        return sessionKey;
    }

    public void createSession(ChannelHandlerContext ctx, String host, int port, String sessionKey, Consumer<NioSocketChannel> consumer) {
        try {
            EventLoopGroup workerGroup = ctx.channel().eventLoop().parent();
            new Bootstrap().group(workerGroup)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new ServerProxyHandler());
                        }
                    })
                    .connect(host, port).addListener((ChannelFuture future) -> {
                        if (future.isSuccess()) {
                            NioSocketChannel channel = (NioSocketChannel) future.channel();
                            sessionChannelMap.put(sessionKey, channel);
                            log.debug("创建代理会话{}成功，当前sessionChannelMap.size={}", sessionKey, sessionChannelMap.size());
                            consumer.accept(channel);
                        }else{
                            log.error("创建代理会话失败，失败原因{}",future.cause());
                            consumer.accept(null);
                        }
                    }
            );
        } catch (Exception ex) {
            consumer.accept(null);
        }

    }

    private String getSeesionKey() {
        String uuid=UUID.randomUUID().toString();
        return "server_"+uuid;
    }

    public NioSocketChannel removeSession(String sessionKey){
       return sessionChannelMap.remove(sessionKey);
    }

    public void closeSeesionChannel(NioSocketChannel bridgeChannel){
        sessionChannelMap.forEach((k,v)->{
            if (v.attr(AttrConstants.BRIDGE_CHANNEL).get().equals(bridgeChannel)) {
                if (v != null) {
                    log.debug("代理通道"+v+"关闭中...");
                    v.attr(AttrConstants.BRIDGE_CHANNEL).set(null);
                    v.close();
                }
            }
        });
    }

    public NioSocketChannel getSessionChannel(String sessionKey){
        return sessionChannelMap.get(sessionKey);
    }

}
